package com.wasu.sdk_ott.http.live

import android.text.TextUtils
import android.util.Log
import com.alibaba.fastjson.JSONArray
import com.alibaba.fastjson.JSONObject
import com.wasu.constant.SYSTEM_CATEGORY_4K_IPDVB_HUIFANG
import com.wasu.constant.SYSTEM_CATEGORY_4K_IPDVB_KANBA
import com.wasu.constant.SYSTEM_CATEGORY_4K_IPDVB_LIVE
import com.wasu.constant.SYSTEM_CATEGORY_4K_IPDVB_QIUSUO
import com.wasu.constant.SYSTEM_CATEGORY_4K_IPDVB_TIMESHIFT
import com.wasu.constant.TAG
import com.wasu.rxcache.RxCache
import com.wasu.rxcache.data.CacheResult
import com.wasu.rxcache.rxCache
import com.wasu.rxcache.stategy.IStrategy
import com.wasu.sdk_ott.http.network.BaseRetrofitFactory
import com.wasu.sdk_ott.utils.WasuTvModelUtil
import io.reactivex.Observer
import io.reactivex.Single
import io.reactivex.SingleObserver
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import java.io.InputStreamReader
import java.util.zip.GZIPInputStream

/**
 * <p>------------------------------------------------------
 * <p>Copyright (C) 2020 wasu company, All rights reserved.
 * <p>------------------------------------------------------
 * <p> IP直播管理系统数据请求
 * <p>
 *
 * @author Created by zhangmz
 * @date on 2023/8/18
 */
class IpLiveService(
    baseUrl: String
): BaseRetrofitFactory(baseUrl) {

    /**
     * 查询分组频道列表，可在主线程调用
     * @param cacheKey 缓存的文件名
     * @param strategy 缓存策略
     */
    fun queryChannelGroupAsync(
        bIds: String? = "",
        isZip: String? = "1",
        category: String? = null,
        cacheKey: String,
        strategy: IStrategy,
        useIpepg: Boolean? = null,
        success: (result: String) -> Unit = {  },
        failure: (e: Throwable) -> Unit =  {  }
    ){
        val isUseIpepg = useIpepg?: isIpepgDomain(category)
        Single.create { emitter ->
            val param = WasuIpLiveUtils().getQueryChannelGroupParam(bIds, isZip = isZip, category = category, isUseIpepg = isUseIpepg)
            emitter.onSuccess(param)
        }.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
            object : SingleObserver<JSONObject> {
                override fun onSubscribe(d: Disposable) {}
                override fun onSuccess(param: JSONObject) {
                    Log.v(TAG, "queryChannelGroupAsync, param:$param")
                    if (isUseIpepg){
                        create(DvbLiveDao::class.java).queryLiveChannelGroupAsync(param)
                    }else {
                        create(IpLiveDao::class.java).queryLiveChannelGroupAsync(param)
                    }
                        .map { decompression(isZip, it, isUseIpepg) }
                        .rxCache(cacheKey, strategy)
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(object : Observer<CacheResult<String>> {
                            override fun onSubscribe(d: Disposable) { }
                            override fun onNext(t: CacheResult<String>) {
                                success(t.data?: "")
                                if (TextUtils.isEmpty(category) || SYSTEM_CATEGORY_4K_IPDVB_LIVE == category){
                                    addAuthorizeChannel(t.data)
                                }
                            }
                            override fun onError(e: Throwable) {
                                failure(e)
                                e.printStackTrace()
                            }
                            override fun onComplete() { }
                        })
                }
                override fun onError(e: Throwable) {
                    e.printStackTrace()
                }
            })
    }

    /**
     * 专门请求IP直播管理系统分组频道，不做缓存
     */
    fun queryIpLiveChannelGroupAsync(
        success: (result: String) -> Unit = {  }
    ){
        Single.create { emitter ->
            val param = WasuIpLiveUtils().getQueryChannelGroupParam(isZip = "1", isUseIpepg = false)
            emitter.onSuccess(param)
        }.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
            object : SingleObserver<JSONObject> {
                override fun onSubscribe(d: Disposable) {}
                override fun onSuccess(param: JSONObject) {
                    Log.v(TAG, "queryIpLiveChannelGroupAsync, param:$param")
                    enqueue(create(IpLiveDao::class.java).queryLiveChannelGroupSync(param), success = { body ->
                        success(decompression("1", body, false))
                    })
                }
                override fun onError(e: Throwable) {
                    e.printStackTrace()
                }
            })
    }

    /**
     * IP直播管理系统查询时移列表
     */
    fun queryIpLiveTimeShiftChannelSync(
        isZip: String? = "1",
        success: (result: String) -> Unit,
        failure: (e: Throwable) -> Unit =  {  }
    ){
        val param = WasuIpLiveUtils().getQueryChannelGroupParam(isZip = isZip, category = SYSTEM_CATEGORY_4K_IPDVB_TIMESHIFT, isUseIpepg = false)
        Log.v(TAG, "queryIpLiveTimeShiftChannelSync, param:$param")
        create(IpLiveDao::class.java).queryLiveTimeShiftListSync(param)
            .execute().body()?.let {
                decompression(isZip, it, false).let(success)
            }?: failure(Throwable("queryIpLiveTimeShiftChannelSync failure, body is null"))
    }

    /**
     * 同步网络请求分组频道，子线程执行
     */
    fun queryChannelGroupSync(
        bIds: String? = "",
        isZip: String? = "1",
        category: String? = null,
        body: JSONObject? = null,
        isUseIpepg: Boolean,
        success: (result: String) -> Unit,
        failure: (e: Throwable) -> Unit =  {  }
    ){
        val param = body?: WasuIpLiveUtils().getQueryChannelGroupParam(bIds, isZip = isZip, category = category, isUseIpepg = isUseIpepg)
        Log.v(TAG, "queryChannelGroupSync, param:$param")
        if (isUseIpepg){
            create(DvbLiveDao::class.java).queryLiveChannelGroupSync(param)
        }else {
            create(IpLiveDao::class.java).queryLiveChannelGroupSync(param)
        }
            .execute().body()?.let {
            decompression(isZip, it, isUseIpepg).let { result ->
                success(result)
                if (TextUtils.isEmpty(category) || SYSTEM_CATEGORY_4K_IPDVB_LIVE == category){
                    addAuthorizeChannel(result)
                }
            }
        }?: failure(Throwable("queryChannelGroupSync failure, bIds：$bIds"))
    }

    /**
     * 查询节目单列表，详细参数注释看下面
     * @see WasuIpLiveUtils.getQueryProgramListParam
     */
    fun queryProgramListAsync(
        type: String,
        getType: String? = "",
        bIds: String? = "",
        bId: String? = "",
        channelId: String? = "",
        beginDate: String? = "",
        endDate: String? = "",
        isZip: String? = "1",
        cacheKey: String,
        category: String? = null,
        strategy: IStrategy,
        rxCache: RxCache,
        isUseIpepg: Boolean,
        success: (result: String) -> Unit = {  },
        failure: (e: Throwable) -> Unit =  {  }
    ){
        if (type.isEmpty()){
            failure(Throwable("Warning!!! queryProgramList, type can not be null"))
            return
        }
        Single.create{ emitter ->
            val param = WasuIpLiveUtils().getQueryProgramListParam(
                type, getType, bIds, bId, channelId, beginDate, endDate, isZip = isZip, category = category, isUseIpepg = isUseIpepg
            )
            emitter.onSuccess(param)
        }.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
            object : SingleObserver<JSONObject> {
                override fun onSubscribe(d: Disposable) {}
                override fun onSuccess(param: JSONObject) {
                    Log.v(TAG, "queryProgramListAsync, param:$param")
                    if (isUseIpepg){
                        create(DvbLiveDao::class.java).queryLiveProgramListAsync(param)
                    }else {
                        create(IpLiveDao::class.java).queryLiveProgramListAsync(param)
                    }
                        .map { decompression(isZip, it, isUseIpepg) }
                        .rxCache(rxCache, cacheKey, strategy)
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(object : Observer<CacheResult<String>> {
                            override fun onSubscribe(d: Disposable) { }
                            override fun onNext(t: CacheResult<String>) {
                                success(t.data?: "")
                            }
                            override fun onError(e: Throwable) {
                                failure(e)
                                e.printStackTrace()
                            }
                            override fun onComplete() { }
                        })
                }
                override fun onError(e: Throwable) {
                    e.printStackTrace()
                }
            })
    }

    /**
     * 同步请求节目单，在子线程调用
     */
    fun queryProgramListSync(
        type: String,
        getType: String? = "",
        bIds: String? = "",
        bId: String? = "",
        channelId: String? = "",
        beginDate: String? = "",
        endDate: String? = "",
        isZip: String? = "1",
        category: String? = null,
        body: JSONObject? = null,
        isUseIpepg: Boolean,
        success: (result: String) -> Unit,
        failure: (e: Throwable) -> Unit =  {  }
    ){
        if (type.isEmpty()){
            failure(Throwable("Warning!!! queryProgramListSync, type can not be null"))
            return
        }
        val param = body?: WasuIpLiveUtils().getQueryProgramListParam(
            type, getType, bIds, bId, channelId, beginDate, endDate, isZip, category = category, isUseIpepg = isUseIpepg
        )
        Log.v(TAG, "queryProgramListSync, param:$param")
        if (isUseIpepg){
            create(DvbLiveDao::class.java).queryLiveProgramListSync(param)
        }else {
            create(IpLiveDao::class.java).queryLiveProgramListSync(param)
        }
            .execute().body()?.let{
            success(decompression(isZip, it, isUseIpepg))
        }?: failure(Throwable("query program is null, type = $type"))
    }

    /**
     * 查询单个频道
     */
    fun queryChannelAsync(
        channelId: String? = "",
        channelName: String? = "",
        category: String? = null,
        success: (result: String) -> Unit,
        failure: (e: Throwable) -> Unit =  {  }
    ){
        if (channelId.isNullOrEmpty() && channelName.isNullOrEmpty()){
            failure(Throwable("Warning!!! channel id and name can not all be null"))
            return
        }
        if (WasuTvModelUtil.isbIpMode()){
            Single.create{ emitter ->
                val param = WasuIpLiveUtils().getQueryChannelParam(channelId, channelName, category = category)
                emitter.onSuccess(param)
            }.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
                object : SingleObserver<JSONObject> {
                    override fun onSubscribe(d: Disposable) {}
                    override fun onSuccess(param: JSONObject) {
                        Log.v(TAG, "queryChannelAsync, param:$param")
                        create(IpLiveDao::class.java).queryLiveChannelAsync(param)
                            .subscribeOn(Schedulers.io())
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe(object : Observer<JSONObject> {
                                override fun onSubscribe(d: Disposable) { }
                                override fun onNext(t: JSONObject) {
                                    success(t.toJSONString())
                                }
                                override fun onError(e: Throwable) {
                                    failure(e)
                                    e.printStackTrace()
                                }
                                override fun onComplete() { }
                            })
                    }
                    override fun onError(e: Throwable) {
                        e.printStackTrace()
                    }
                })
        }else {
            verifyAuthorizeChannel(channelId){
                it?.let {
                    // 保持缓存中和接口数据结构一致
                    val bouChJsonObject = JSONObject()
                    bouChJsonObject["result"] = "0"
                    val chListJsonArray = JSONArray()
                    chListJsonArray.add(it)
                    bouChJsonObject["chList"] = chListJsonArray
                    success(bouChJsonObject.toString())
                }?: failure(Throwable("queryChannelAsync, query dvb channel info is null"))
            }
        }
    }

    /**
     * 同步查询单个频道详情
     */
    fun queryChannelSync(
        channelId: String? = "",
        channelName: String? = "",
        category: String? = null,
        success: (result: String) -> Unit,
        failure: (e: Throwable) -> Unit =  {  }
    ){
        if (channelId.isNullOrEmpty() && channelName.isNullOrEmpty()){
            failure(Throwable("Warning!!! channel id and name can not all be null"))
            return
        }
        if (WasuTvModelUtil.isbIpMode() || category == SYSTEM_CATEGORY_4K_IPDVB_KANBA || category == SYSTEM_CATEGORY_4K_IPDVB_HUIFANG || category == SYSTEM_CATEGORY_4K_IPDVB_QIUSUO){
            val param = WasuIpLiveUtils().getQueryChannelParam(channelId, channelName, category = category)
            Log.v(TAG, "queryChannelSync, param:$param")
            create(IpLiveDao::class.java).queryLiveChannelSync(param)
                .execute().body()?.let {
                    success(it.toString())
                }?: failure(Throwable("queryChannelExecute failure, channelId:$channelId; channelName:$channelName"))
        }else {
            verifyAuthorizeChannel(channelId){
                it?.let {
                    // 保持缓存中和接口数据结构一致
                    val bouChJsonObject = JSONObject()
                    bouChJsonObject["result"] = "0"
                    val chListJsonArray = JSONArray()
                    chListJsonArray.add(it)
                    bouChJsonObject["chList"] = chListJsonArray
                    success(bouChJsonObject.toString())
                }?: failure(Throwable("queryChannelAsync, query dvb channel info is null"))
            }
        }
    }

    /**
     * 查询频道授权列表，DVB模式适用
     */
    fun queryChannelAuthAsync(
        cacheKey: String,
        strategy: IStrategy,
        rxCache: RxCache,
        success: (result: String) -> Unit,
        failure: (e: Throwable) -> Unit =  {  }
    ){
        Single.create{ emitter ->
            val param = WasuIpLiveUtils().getQueryChannelAuthParam()
            emitter.onSuccess(param)
        }.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
            object : SingleObserver<JSONObject> {
                override fun onSubscribe(d: Disposable) {}
                override fun onSuccess(param: JSONObject) {
                    Log.v(TAG, "queryChannelAuthAsync, param:$param")
                    create(DvbLiveDao::class.java).queryLiveChannelAuthAsync(param)
                        .map { it.toJSONString() }
                        .rxCache(rxCache, cacheKey, strategy)
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(object : Observer<CacheResult<String>> {
                            override fun onSubscribe(d: Disposable) { }
                            override fun onNext(t: CacheResult<String>) {
                                success(t.data?: "")
                            }
                            override fun onError(e: Throwable) {
                                failure(e)
                                e.printStackTrace()
                            }
                            override fun onComplete() { }
                        })
                }
                override fun onError(e: Throwable) {
                    e.printStackTrace()
                }
            })
    }

    /**
     * 查询分组频道节目单等版本信息，用来更新UI层数据
     * @see WasuIpLiveUtils.getQueryVersionParam 入参明细见此类
     */
    fun queryChannelVersionAsync(
        type: String? = "0",
        chId: String? = "",
        success: (result: String) -> Unit,
        failure: (e: Throwable) -> Unit =  {  }
    ){
        val isUseIpepg = isIpepgDomain()
        Single.create{ emitter ->
            val param = WasuIpLiveUtils().getQueryVersionParam(type, chId, isUseIpepg = isUseIpepg)
            emitter.onSuccess(param)
        }.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
            object : SingleObserver<JSONObject> {
                override fun onSubscribe(d: Disposable) {}
                override fun onSuccess(param: JSONObject) {
                    Log.v(TAG, "queryChannelVersionAsync, param:$param")
                    if (isUseIpepg){
                        create(DvbLiveDao::class.java).queryLiveVersionAsync(param)
                    }else {
                        create(IpLiveDao::class.java).queryLiveVersionAsync(param)
                    }
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(object : Observer<JSONObject> {
                            override fun onSubscribe(d: Disposable) { }
                            override fun onNext(t: JSONObject) {
                                success(t.toJSONString())
                            }
                            override fun onError(e: Throwable) {
                                failure(e)
                                e.printStackTrace()
                            }
                            override fun onComplete() { }
                        })
                }
                override fun onError(e: Throwable) {
                    e.printStackTrace()
                }
            })
    }

    /**
     * isZip = 1，数据解压，否则json类型
     */
    private fun decompression(
        isZip: String?,
        body: ResponseBody,
        isUseIpepg: Boolean
    ): String{
        return runCatching {
            Log.v(TAG, "decompression, isUseIpepg:$isUseIpepg; isZip:$isZip")
            if (!isUseIpepg && "1" == isZip){
                val byteStream = body.byteStream()
                val zipInputStream = GZIPInputStream(byteStream)
                val isr = InputStreamReader(zipInputStream)
                val content = isr.readText()
                byteStream.close()
                zipInputStream.close()
                content
            }else {
                body.string()
            }
        }.onFailure {
            Log.e(TAG, "decompression, error:$it")
        }.getOrDefault("")
    }

}